from logging import getLogger

import zope.interface

from lxml import etree

from meercat.base.instance import Instance
from meercat.base.metadata import Metadata

from meercat.harvester.base.interfaces import IFileHarvester, IFileSource
from meercat.harvester.base.exceptions import HarvesterException



log = getLogger('meercat.harvester.metalib.harvester')

class MetalibHarvester(object):
    zope.interface.implements(IFileHarvester)

    def __init__(self, source, **kwargs):
        """ source_function should be a callable function/object that returns
        a file-like object or other etree.parse parseable object. Source is the
        source name. This is pre-pended with metalib:// when creating instances"""
        super(MetalibHarvester, self).__init__()
        self.setSource(source)
        
        if kwargs.get('fileSource',None):
            self.fileSource = kwargs['fileSource']
        
    def getSource(self):
        return self._source

    def setSource(self, name):
        self._source = name
        
    def getFileSource(self):
        return self._fileSource
    
    def setFileSource(self, source):
        self._fileSource = IFileSource(source)
    
    fileSource = property(getFileSource, setFileSource)
    
    def harvest(self):
        """ Call the self._source_function function to get the parseable data
        then use that with etree to create instances and metadata """
        fh = self.fileSource()

        if hasattr(fh,'read'):
            fh = [fh]

        ku_tag = 'knowledge_unit'
        record_tag = 'record'

        instances = []
        exclude = ('find_module', 'present_module','external_conf',
                   'program_name','present_single')

        source = u'metalib://%s' % (unicode(self.getSource()))

        for handle in fh:
            try:
                doc = etree.parse(handle,
                                  etree.XMLParser(recover=True,
                                                  remove_blank_text=True)).getroot()
                
                for tempelem in doc.getiterator():
                    try:
                        if tempelem.tag.startswith("{"):
                            tempelem.tag = tempelem.tag.split("}")[1]
                    except Exception, e:
                        log.error('Exception while stripping tags: %s' % (str(e),))
                        import sys, traceback
                        for line in traceback.format_exception(*sys.exc_info()):
                            log.error(line)

                for ku in doc.getiterator(ku_tag):
                    try:
                        metadata = []
                        identifier = None
                        for child in ku.getchildren():
                            try:
                                if child.tag.lower() in exclude:
                                    continue
                                
                                replacement = etree.Element(child.tag,
                                                            child.attrib)
                                replacement.extend(child.getchildren())
                                
                                if child.tag == record_tag:
                                    identifier = unicode(replacement.getchildren()[0].text, 'utf-8')
                                    metadata.append(Metadata(source=source,
                                                             format=u'metalib.marcxml',
                                                             value=etree.tostring(replacement,
                                                                                  encoding=unicode)))
                                else:
                                    metadata.append(Metadata(source=source,
                                                             format=u'metalib.%s' % (replacement.tag.lower(),),
                                                             value=etree.tostring(replacement,
                                                                                  encoding=unicode)))
                            except Exception, e:
                                log.error('Error while handling a child tag (%s): %s' % (str(child.tag),str(e)))
                                import sys, traceback
                                for line in traceback.format_exception(*sys.exc_info()):
                                    log.error(line)
                        
                        if identifier and len(metadata) > 0:
                            instances.append(Instance(source=source,
                                                      identifier=identifier,
                                                      metadata = metadata))
                        else:
                            log.error('Error parsing a knowledge unit, no identifier or metadata')
                            import sys, traceback
                            for line in traceback.format_exception(*sys.exc_info()):
                                log.error(line)
                    except Exception, e:
                        log.error('Error while handling a knowledge unit: %s' % (str(e),))
                        import sys, traceback
                        for line in traceback.format_exception(*sys.exc_info()):
                            log.error(line)
            except Exception, e:
                log.error('Exception while handling a file: %s' % (str(e)))
                import sys, traceback
                for line in traceback.format_exception(*sys.exc_info()):
                    log.error(line)

        return instances